package com.example.ytyproject.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.ytyproject.config.SecurityUtil;
import com.example.ytyproject.config.exception.AppException;
import com.example.ytyproject.entity.*;
import com.example.ytyproject.entity.vo.PermissionAllocationVo;
import com.example.ytyproject.mapper.MenuMapper;
import com.example.ytyproject.service.MenuService;
import com.example.ytyproject.service.RoleMenuService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    @Autowired
    private MenuMapper menuMapper;
    @Autowired
    private RoleMenuService roleMenuService;
    @Override
    public PermissionAllocationVo tree(String roleId) {
        // 1 查询所有的部门
        List<Menu> list = menuMapper.selectList(null);
        list.forEach(e -> {
            Meta meta = new Meta();
            meta.setIcon(e.getIcon()).setTitle(e.getTitle());
            e.setMeta(meta);
        });
        // 2 查询最顶级部门
        List<String> enableNodess = new ArrayList<>();
        Menu dept = menuMapper.selectById("1");
        List<RoleMenu> roleMenus = roleMenuService.findByRoleId(roleId);
        Menu trees = getTrees(dept, list, roleMenus, enableNodess);
        Meta meta = new Meta();
        meta.setIcon(trees.getIcon()).setTitle(trees.getTitle());
        trees.setMeta(meta);

        PermissionAllocationVo allocationVo = new PermissionAllocationVo();
        allocationVo.setMenu(trees).setMenuId(enableNodess).setRoleId(roleId);
        return allocationVo;
    }

    @Override
    public void addData(Menu param) {
        // 1 校验数据
        Menu menu = findByCode(param.getCode());
        if (menu != null) {
            throw new AppException("菜单编码已存在，请重新输入");
        }
        if (StringUtils.isEmpty(param.getIcon())) {
            param.setIcon("Menu");//给默认图标
        }
        param.setParentId(param.getId())
                .setTitle(param.getName())
                .setCreateDate(LocalDateTime.now())
                .setUpdateDate(LocalDateTime.now())
                .setEnable(true)
                .setCreateId(SecurityUtil.getUserId());
        param.setId(null);
        this.save(param);
    }

    @Override
    public void updateData(Menu param) {
        Menu menu = findByCode(param.getCode());
        if (menu != null) {
            if (!menu.getId().equals(param.getId())) {
                throw new AppException("菜单编码已存在，请重新输入");
            }
        }
        param.setUpdateDate(LocalDateTime.now())
                .setUpdateId(SecurityUtil.getUserId());
        this.updateById(param);
    }

    @Override
    public Menu findByCode(String code) {
        Menu menu = this.getOne(new QueryWrapper<Menu>().lambda().eq(Menu::getCode, code));
        return menu;
    }

    @Override
    public List<Menu> listMenus() {
        // 1 查询所有的部门
        List<Menu> list = menuMapper.selectList(null);
        list.forEach(e -> {
            Meta meta = new Meta();
            meta.setIcon(e.getIcon()).setTitle(e.getTitle());
            e.setMeta(meta);
        });
        // 2 查询最顶级部门
        Menu dept = menuMapper.selectById("1");
        List<RoleMenu> roleMenus = new ArrayList<>();
        User user = SecurityUtil.getUser();
        List<Role> roles = user.getRoles();
        for (Role role : roles) {
            List<RoleMenu> roleMenus1 = roleMenuService.findByRoleId(role.getId());
            if (roleMenus1.size() > 0) {
                roleMenus.addAll(roleMenus1);
            }
        }
        List<Menu> menus = new ArrayList<>();
        for (RoleMenu roleMenu : roleMenus) {
            // 取出所有菜单的上级数据
            String menuId = roleMenu.getMenuId();
            Optional<Menu> first = list.stream().filter(e -> e.getId().equals(menuId)).findFirst();
            Menu menu = first.get();
            menus.add(menu);
            while (true) {
                String parentId = menu.getParentId();
                if (parentId.equals("0")) {
                    break;
                }
                Optional<Menu> first1 = list.stream().filter(e -> e.getId().equals(parentId)).findFirst();
                menu = first1.get();
                menus.add(menu);
            }
        }
        ArrayList<Menu> collect = menus.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Menu::getId))), ArrayList::new));
        Menu trees = getTrees(dept, collect, null, null);
        return trees.getChildren();
    }

    /**
     * 递归遍历查询数
     * @param node
     * @param list
     * @return
     */
    public Menu getTrees(Menu node, List<Menu> list, List<RoleMenu> roleMenus, List<String> enableNodess) {
        if (roleMenus != null && roleMenus.size() > 0) {
            Optional<RoleMenu> first = roleMenus.stream().filter(e -> e.getMenuId().equals(node.getId())).findFirst();
            first.ifPresent(e -> enableNodess.add(node.getId()));
        }
        String value = node.getId();
        List<Menu> childs = null;
        Iterator<Menu> iterator = list.iterator();
        while (iterator.hasNext()) {
            Menu m = iterator.next();
            if(m.getParentId().equals(value)){
                childs = node.getChildren();
                if(childs == null) {
                    childs = new ArrayList<>();
                }
                childs.add(m);
                iterator.remove();
                node.setChildren(childs);
            }
        }
        if(childs != null && !childs.isEmpty() && !list.isEmpty()){
            Iterator<Menu> iterator2 = childs.iterator();
            while(iterator2.hasNext()){
                Menu next = iterator2.next();
                getTrees(next,list, roleMenus, enableNodess);
            }
        }
        return node;
    }
}
